import { verifyPhone, verifyStrBlank } from './verification'
// 邮政编码
function validPostcode(rule, value, callback) {
    if (value == "") {
        callback(new Error(rule.message))
    } else {
        let pattern = /^[0-9]{6}$/;
        let flag = pattern.test(value);
        if (!flag) {
            callback(new Error('请输入正确的邮政编码'))
        } else {
            callback()
        }
    }
}
// 空格
function validEmpty(value) {
    return value === '' || value === null || value === undefined
}

// 手机号
function validPhone(rule, value, callback) {
    if (!verifyPhone(value)) {
        callback(new Error('请输入正确的手机号码'))
    } else {
        callback()
    }
}
// 验证空白
function validBlank(rule, value, callback) {
    if (typeof (value) == 'string' && (value === null || value === undefined || value === '')) {
        callback(new Error(`请输入${rule.newMessage}`))
    } else {
        if (typeof (value) == 'string') {
            if (verifyStrBlank(value)) {
                callback(new Error(`${rule.newMessage}头尾不能有空格`))
            } else {
                callback()
            }
        } else {
            callback()
        }

    }
}
// 邮箱
function validMail(rule, value, callback) {
    let reg = new RegExp("^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$"); //正则表达式
    if (!value) {
        callback(new Error(rule.message))
    } else if (!reg.test(value)) {
        callback(new Error('请输入正确的邮箱'))
    } else {
        callback()
    }
}
// 座机电话
function validTelePhone(rule, value, callback) {
    const reg = /0\d{2,3}-\d{7,8}/
    if (!rule.required && value === ""||!rule.required && value === null) {
        callback()
    } else if (!reg.test(value)) {
        callback(new Error('请输入正确的座机号码'))
    } else {
        callback()
    }
}
// 是否为数组
function validArray(rule, value, callback) {
    if (!Array.isArray(value)) {
        callback(new Error(rule.message))
    } else if (value.length === 0) {
        callback(new Error(rule.message))
    } else {
        callback()
    }
}
// 身份证
function validateIdCard(rule, value, callback) {
    let regIdCard = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/;
    if (!value) {
        callback(new Error(rule.message))
    }
    if (regIdCard.test(value)) {
        if (value.length == 18) {
            let idCardWi = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);//将前17位加权因子保存在数组里
            let idCardY = new Array(1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2);//这是除以11后，可能产生的11位余数、验证码，也保存成数组
            let idCardWiSum = 0;//用来保存前17位各自乖以加权因子后的总和
            for (let i = 0; i < 17; i++) {
                idCardWiSum += value.substring(i, i + 1) * idCardWi[i];
            }
            let idCardMod = idCardWiSum % 11;//计算出校验码所在数组的位置
            let idCardLast = value.substring(17);//得到最后一位身份证号码
            //如果等于2，则说明校验码是10，身份证号码最后一位应该是X
            if (idCardMod == 2) {
                if (idCardLast == "X" || idCardLast == "x") {
                    callback()
                } else {
                    callback(new Error('请输入正确的身份证号'))
                }
            } else {
                //用计算出的验证码与最后一位身份证号码匹配，如果一致，说明通过，否则是无效的身份证号码
                if (idCardLast == idCardY[idCardMod]) {
                    callback()
                } else {
                    callback(new Error('请输入正确的身份证号'))
                }
            }
        } else {
            callback(new Error('请输入正确的身份证号'))
        }
    } else {
        callback(new Error('请输入正确的身份证号'))
    }
}
// 是否为数字
function validNum(rule, value, callback) {
    isNaN(Number(value)) ? callback(new Error(rule.message)) : callback()
}

function validPositive(rule, value, callback) {
    value < 0 ? callback(new Error(rule.message)) : callback()
}
// 整数
function validInteger(rule, value, callback) {
    const reg = /^[0-9]\d*$/
    reg.test(value) ? callback() : callback(new Error(rule.message))
}
// 价格(保留2位)
function validPrice(rule, value, callback) {
    const reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^[0-9]\.[0-9]([0-9])?$)/;
    reg.test(value) ? callback() : callback(new Error(rule.message))
}
// 是否名称重复
function validDuplic(rule, value, callback) {
    if (!Array.isArray(rule.duplicData)) {
        throw new Error('duplicData is not Array Type!')
    }
    rule.duplicData.includes(value) ? callback(new Error(rule.message)) : callback()
}

function validCompare(rule, value, callback) {
    if (typeof rule.handler !== 'function') {
        throw new Error('handler is not a Function!')
    }
    rule.handler(value) ? callback() : callback(new Error(rule.message))
}
// 最大长度
function validMaxlength(rule, value, callback) {
    String(value).length > rule.maxlength ? callback(new Error(rule.message)) : callback()
}
// 最小长度
function validMinlength(rule, value, callback) {
    if (!rule.required && validEmpty(value)) {
        callback()
        return
    }
    String(value).length < rule.minlength ? callback(new Error(rule.message)) : callback()
}
function validMax(rule, value, callback) {
    parseFloat(value) > parseFloat(rule.max) ? callback(new Error(rule.message)) : callback()
}

function validMin(rule, value, callback) {
    parseFloat(value) < parseFloat(rule.min) ? callback(new Error(rule.message)) : callback()
}
// 中文
function validChinese(rule, value, callback) {
    const reg = /^[\u4E00-\u9FA5]{1,5}$/;
    if (!value) {
        callback(new Error(rule.message))
    } else if (!reg.test(value)) {
        callback(new Error('请输入中文'))
    } else {
        callback()
    }
}
// 数字和字母
function validAccount(rule, value, callback) {
    const reg = /^[0-9a-zA-Z]*$/;
    if (!value) {
        callback(new Error(rule.message))
    } else if (!reg.test(value)) {
        callback(new Error('请输入字母和数字组合'))
    } else {
        callback()
    }
}
// 不验证都通过
function validNoRequire(rule, val, callback) {
    callback()
}
function getDefaultRule(type) {
    const map = {
        required: {},
        array: {
            validator: validArray
        },
        number: {
            validator: validNum
        },
        phone: {
            validator: validPhone
        },
        mail: {
            validator: validMail
        },
        idCard: {
            validator: validateIdCard
        },
        integer: {
            validator: validInteger
        },
        price: {
            validator: validPrice
        },
        duplic: {
            validator: validDuplic
        },
        positive: {
            validator: validPositive
        },
        compare: {
            validator: validCompare
        },
        maxlength: {
            validator: validMaxlength
        },
        minlength: {
            validator: validMinlength
        },
        max: {
            validator: validMax
        },
        min: {
            validator: validMin
        },
        postcode: {
            validator: validPostcode
        },
        telePhone: {
            validator: validTelePhone
        },
        Chinese: {
            validator: validChinese
        },
        account: {
            validator: validAccount
        },
        'no-required': {
            validator: validNoRequire
        }

    }
    return map[type]
}

/**
 * 获取form表单规则
 * @param {String} type 验证类型
 *  required: 必填项
 *  maxlength: 字段最大长度
 *  minlength: 字段最小长度
 *  max: 最大数额
 *  min: 最小数额
 *  number: 验证是否为数字
 *  phone: 验证手机格式
 *  integer: 验证是否为整数
 *  duplic: 数据重复校验
 *  positive: 验证是否为正数
 *  compare: 数据比较，一般用来比较大小
 *  Chinese: 中文
 *  idCard: 身份证
 *  telePhone: 座机
 *  account: 字母和数字组合
 * @param {Object} config 配置项
 *      required: 是否必选，影响表单前的 * 号显示
 *      trigger: 触发方式  'blur' | 'change' | ['change', 'blur']
 *      message: 验证失败提示语
 *      maxlength: type为 maxlength 时必传
 *      minlength: type为 minlength 时必传
 *      max: type为 max 时必传
 *      min: type为 min 时必传
 *      duplicData {Array}: type为 duplic 时必传，需要进行对比的来源集合
 *      handler {Function}: type为 compare 时必传，进行比较时执行的方法，返回布尔值来表示验证结果
 */

export function getFormRule(type = 'required', config = {}) {
    return Object.assign({}, getDefaultRule(type), config)
}

function getDefaultConfig(type, field, config = {}) {
    const _config = {
        required: true,
        trigger: 'change'
    }
    switch (type) {
        case 'input':
            _config.message = `请输入${field}`
            break
        case 'select':
            _config.message = `请选择${field}`
            break
        case 'upload':
            _config.message = `请上传${field}`
            break
        case 'no-required':
            _config.required = false
            break
        case 'required':
            _config.message = `${field}不能为空`
            break
        case 'maxlength':
            _config.message = `${field}长度不能大于${config.maxlength}`
            break
        case 'minlength':
            _config.message = `${field}长度不能小于${config.minlength}`
            break
        case 'max':
            _config.message = `${field}数额不能大于${config.max}`
            break
        case 'min':
            _config.message = `${field}数额不能小于${config.min}`
            break
        case 'number':
            _config.message = `${field}必须为数字`
            break
        case 'integer':
            _config.message = `${field}必须为整数`
            break
        case 'price':
            _config.message = `${field}填写有误`
            break
        case 'positive':
            _config.message = `${field}必须为正数`
            break
        case 'duplic':
            _config.message = `${field}不能重复`
            break
        case 'compare':
            _config.message = `请输入正确的${field}`
            break
    }
    return _config
}

/**
 * 对 getFormRule 进行了一层封装，增加了一些默认的配置
 * @param {String} type
 *  input: 输入框校验
 *  select: 下拉选择框校验
 *  upload: 上传
 *  其他参考 getFormRule
 * @param {String} field 校验的字段名称
 * @param {Object} config 参考 getFormRule，会覆盖默认的配置
 */
export function getRules(type, field, config = {}) {
    config = Object.assign({}, getDefaultConfig(type, field, config), config)
    // 更改type值
    type = ['input', 'select', 'upload'].includes(type) ? 'required' : type
    let rules = []
    if (type === 'required') {
        rules = [{ validator: validBlank }, getFormRule(type, config)]
        rules[0].newMessage = field
    } else {
        if (config.required === 'no-required') {
            const _config = Object.assign({}, config, getDefaultConfig('no-required', field))
            rules.unshift(getFormRule(type, _config))
        } else {
            rules = [getFormRule(type, config)]
        }
    }
    if (type === 'positive') {
        const _config = Object.assign({}, config, getDefaultConfig('number', field))
        // 以 _config 为最后合并对象
        rules.unshift(getFormRule('number', _config))
    }
    if (type !== 'required' && config.required) {
        const _config = Object.assign({}, config, getDefaultConfig('required', field))
        rules.unshift(getFormRule('required', _config))
    }
    return rules
}

export default {
    getFormRule,
    getRules
}
